# -*- coding: utf-8 -*-
import sys
import os
import json
import util
from xml.dom.minidom import parse


# @param path 检查该目录是否为 android gradle module
def is_module(path: str) -> bool:
    # path必须是文件夹才能是android模块
    if not os.path.isdir(path):
        return False

    build_gradle = os.path.join(path, "build.gradle")
    build_gradle_kts = os.path.join(path, "build.gradle.kts")
    if util.exists(build_gradle) or util.exists(build_gradle_kts):
        return True
    else:
        return False


# 收集Android项目中所有模块的路径
def traversal_module(path: str, list: list):
    if is_module(path):
        list.append(path)

    if os.path.isdir(path):
        for file in os.listdir(path):
            filepath = os.path.join(path, file)
            traversal_module(filepath, list)


# 获取所有模块中的单元测试结果xml文件
def get_unit_test_xmls(path_list: list) -> list:
    # 使用 set 集合，去重复
    xml_sets = set([])
    for module_path in path_list:
        unit_test_path = os.path.join(
            module_path, "build", "test-results", "testReleaseUnitTest"
        )
        if util.exists(unit_test_path):
            for root, _, files in os.walk(unit_test_path):
                for file in files:
                    if file.startswith("TEST-") and file.endswith(".xml"):
                        xml_path = os.path.join(root, file)
                        xml_sets.add(xml_path)

    # set to list
    return list(xml_sets)


# 解析出 testsuite 节点
def read_testsuite(node) -> dict:
    # name="com.example.unittestdemo.RobolectricTest" tests="5" skipped="0" failures="1" errors="0" timestamp="2024-05-03T03:11:08" hostname="LHL" time="4.91"
    name = node.getAttribute("name")
    tests = node.getAttribute("tests")
    skipped = node.getAttribute("skipped")
    failures = node.getAttribute("failures")
    errors = node.getAttribute("errors")
    timestamp = node.getAttribute("timestamp")
    hostname = node.getAttribute("hostname")
    time = node.getAttribute("time")
    data = {
        "name": name,
        "tests": tests,
        "skipped": skipped,
        "failures": failures,
        "errors": errors,
        "timestamp": timestamp,
        "hostname": hostname,
        "time": time,
    }
    return data


# 解析出 testcase 节点
def read_testcase(node) -> dict:
    # name="testStaticMethod" classname="com.example.unittestdemo.RobolectricTest" time="3.256"
    # failure

    name = node.getAttribute("name")
    classname = node.getAttribute("classname")
    time = node.getAttribute("time")

    failureNodes = node.getElementsByTagName("failure")
    # 存在失败的数据，表示该单元测试函数运行结果不符合预期
    success = len(failureNodes) <= 0

    data = {"name": name, "classname": classname, "time": time, "success": success}
    return data


# 解析出 xml文件 中所有 testsuite 节点
def read_unit_test_xml(path: str) -> dict:
    dom = parse(path)
    rootNode = dom.documentElement

    testsuite = read_testsuite(rootNode)

    testcases = []
    testcaseNodes = rootNode.getElementsByTagName("testcase")
    for j in range(len(testcaseNodes)):
        testcaseNode = testcaseNodes[j]
        testcase = read_testcase(testcaseNode)
        testcases.append(testcase)

    testsuite["testcases"] = testcases


    return testsuite


# 解析所有xml文件的数据
def read_unit_test_xmls(list: list) -> list:
    _list = []
    for path in list:
        json_data = read_unit_test_xml(path)
        _list.append(json_data)
    return _list


# 读取项目中的单元测试结果
# @param project_path 项目根目录
def read_unit_test(project_path: str) -> dict:
    list = []
    # 找出Android项目中所有模块
    traversal_module(project_path, list)
    # 找出所有模块的单元测试结果
    xmls = get_unit_test_xmls(list)
    # 解析所有单元测试结果 xml -> json
    json_list = read_unit_test_xmls(xmls)

    # 单元测试函数总数量
    total = 0
    # 单元测试通过函数数量
    passed = 0
    # 单元测试总体耗时，单位：秒
    time = 0.0

    for json in json_list:
        # json 是运行单元测试函数的class，单元测试函数需在一个class下编写
        tests = json["tests"]  # 一共参与了多少个函数
        skipped = json["skipped"]  # 跳过执行多少个函数
        failures = json["failures"]  # 执行函数结果，不在预期范围之内（属于失败）
        errors = json["errors"]  # 执行过程中出现了异常（属于失败）
        _time = json["time"]  # 总耗时，单位：秒

        _total = int(tests) - int(skipped)
        _passed = _total - (int(failures) + int(errors))
    

        total += _total
        passed += _passed
        time += float(_time)

    # 浮点运算，保留3位小数
    time = round(time,3)
    return {"total": total, "passed": passed, "time": time}


# def main() -> int:
#     json_obj = read_unit_test(r"D:\workspace01\Android-APT\UnitTestCoverageDemo")
#     print(json.dumps(json_obj))
#     return 0


# # main函数入口
# if __name__ == "__main__":
#     sys_ret = main()
#     sys.exit(sys_ret)
